#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import uuid
import json
import datetime
import time
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                             QHBoxLayout, QLabel, QPushButton, QLineEdit, 
                             QFileDialog, QScrollArea, QMessageBox, QProgressBar,
                             QGridLayout, QSizePolicy, QListWidget, QListWidgetItem)
from PyQt5.QtCore import Qt, QMimeData, QUrl, QThread, pyqtSignal, QSize
from PyQt5.QtGui import QPixmap, QDragEnterEvent, QDropEvent, QImageReader, QImage, QTransform, QPainter
import config

class UploadThread(QThread):
    """上传线程，处理文件上传并发送进度信号"""
    update_progress = pyqtSignal(int, str)  # 总体进度和当前文件
    update_file_progress = pyqtSignal(int)  # 当前文件进度
    upload_finished = pyqtSignal(list, list)  # 成功列表和失败列表
    
    def __init__(self, files, upload_dir):
        super().__init__()
        self.files = files
        self.upload_dir = upload_dir
        
        # 初始化腾讯云COS客户端
        cos_config = CosConfig(
            Region=config.REGION,
            SecretId=config.SECRET_ID,
            SecretKey=config.SECRET_KEY
        )
        self.client = CosS3Client(cos_config)
        
    def run(self):
        """执行上传任务"""
        success_files = []
        failed_files = []
        total_files = len(self.files)
        
        for index, file_path in enumerate(self.files):
            try:
                # 获取文件扩展名
                file_ext = os.path.splitext(file_path)[1].lower()
                if not file_ext:
                    file_ext = '.jpg'  # 默认扩展名
                
                # 生成时间戳文件名 (yyyymmddhhmmss)
                current_time = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
                # 如果同一秒内上传多张图片，添加毫秒和索引确保唯一性
                milliseconds = int(time.time() * 1000) % 1000
                new_filename = f"{current_time}_{milliseconds}_{index}{file_ext}"
                
                # 构建对象存储路径 - 添加以yyyymmdd格式命名的二级目录
                today_date = datetime.datetime.now().strftime("%Y%m%d")
                cos_key = f"{config.PREFIX}{self.upload_dir}/{today_date}/{new_filename}"
                
                # 更新总体进度
                progress = int((index / total_files) * 100)
                self.update_progress.emit(progress, new_filename)
                
                # 定义上传进度回调
                def upload_progress_callback(consumed_bytes, total_bytes):
                    if total_bytes:
                        progress = int((consumed_bytes / total_bytes) * 100)
                        self.update_file_progress.emit(progress)
                
                # 上传文件到腾讯云COS
                response = self.client.upload_file(
                    Bucket=config.BUCKET,
                    LocalFilePath=file_path,
                    Key=cos_key,
                    progress_callback=upload_progress_callback
                )
                
                # 上传成功
                success_files.append((file_path, new_filename))
                
            except Exception as e:
                # 上传失败
                failed_files.append((file_path, str(e)))
                
        # 发送上传完成信号
        self.upload_finished.emit(success_files, failed_files)

class ThumbnailWidget(QWidget):
    """缩略图显示控件"""
    remove_requested = pyqtSignal(str)  # 发送删除请求的信号，参数为图片路径
    
    def __init__(self, file_path, parent=None):
        super().__init__(parent)
        self.file_path = file_path
        self.initUI()
        
    def initUI(self):
        """初始化界面"""
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(5, 5, 5, 5)
        self.setLayout(self.layout)
        
        # 添加删除按钮
        self.delete_button = QPushButton("×")
        self.delete_button.setStyleSheet("""
            QPushButton {
                background-color: rgba(255, 0, 0, 0.7);
                color: white;
                border-radius: 10px;
                font-weight: bold;
                max-width: 20px;
                max-height: 20px;
                min-width: 20px;
                min-height: 20px;
            }
            QPushButton:hover {
                background-color: red;
            }
        """)
        self.delete_button.clicked.connect(self.request_remove)
        
        # 顶部布局，右侧放删除按钮
        top_layout = QHBoxLayout()
        top_layout.addStretch()
        top_layout.addWidget(self.delete_button)
        self.layout.addLayout(top_layout)
        
        # 获取图片信息
        reader = QImageReader(self.file_path)
        size = reader.size()
        
        # 创建图片容器和标签
        self.image_container = QWidget()
        self.image_container.setFixedSize(120, 120)
        
        # 图片标签
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignCenter)
        
        # 使用基本布局确保图片居中
        container_layout = QVBoxLayout(self.image_container)
        container_layout.addWidget(self.image_label)
        container_layout.setAlignment(Qt.AlignCenter)
        
        # 加载并显示图片
        if size.width() <= 0 or size.height() <= 0:
            # 图片无效
            self.image_label.setText("无效图片")
            print(f"无效图片尺寸: {self.file_path}")
        else:
            try:
                image = QImage(self.file_path)
                is_portrait = size.height() > size.width()
                
                # 显示图片信息
                print(f"图片: {os.path.basename(self.file_path)}, 尺寸: {size.width()}x{size.height()}, 竖屏: {is_portrait}")
                
                # 根据图片方向使用不同的缩放方法
                if is_portrait:
                    # 竖屏图片 - 高度使用最大值，宽度按比例
                    max_height = 100
                    scaled_width = int(size.width() * max_height / size.height())
                    pixmap = QPixmap.fromImage(image.scaled(
                        scaled_width, max_height, 
                        Qt.KeepAspectRatio, Qt.SmoothTransformation
                    ))
                    print(f"竖屏缩放: {scaled_width}x{max_height}")
                else:
                    # 横屏图片 - 宽度使用最大值，高度按比例
                    max_width = 100
                    scaled_height = int(size.height() * max_width / size.width())
                    pixmap = QPixmap.fromImage(image.scaled(
                        max_width, scaled_height, 
                        Qt.KeepAspectRatio, Qt.SmoothTransformation
                    ))
                    print(f"横屏缩放: {max_width}x{scaled_height}")
                
                self.image_label.setPixmap(pixmap)
                print(f"设置pixmap尺寸: {pixmap.width()}x{pixmap.height()}")
            
            except Exception as e:
                self.image_label.setText("加载错误")
                print(f"加载图片错误: {str(e)}")
        
        # 添加图片容器到布局
        self.layout.addWidget(self.image_container)
        
        # 文件名标签
        filename = os.path.basename(self.file_path)
        if len(filename) > 15:
            filename = filename[:12] + "..."
        self.name_label = QLabel(filename)
        self.name_label.setAlignment(Qt.AlignCenter)
        self.layout.addWidget(self.name_label)
        
        # 设置整体大小
        self.setFixedSize(130, 180)
    
    def request_remove(self):
        """请求删除此图片"""
        self.remove_requested.emit(self.file_path)

class CustomLabel(QLabel):
    """自定义标签，支持拖放事件处理"""
    def __init__(self, text, parent=None):
        super().__init__(text, parent)
        self.setAcceptDrops(True)
        self.parent = parent
        
    def dragEnterEvent(self, event):
        if self.parent and hasattr(self.parent, 'dragEnterEvent'):
            self.parent.dragEnterEvent(event)
            
    def dragMoveEvent(self, event):
        if self.parent and hasattr(self.parent, 'dragMoveEvent'):
            self.parent.dragMoveEvent(event)
    
    def dropEvent(self, event):
        if self.parent and hasattr(self.parent, 'dropEvent'):
            self.parent.dropEvent(event)

class ImageUploaderApp(QMainWindow):
    """图片上传主窗口"""
    def __init__(self):
        super().__init__()
        self.selected_files = []
        self.upload_thread = None
        self.current_preview_file = None  # 当前预览的文件
        self.initUI()
        
    def initUI(self):
        """初始化主界面"""
        # 设置窗口属性
        self.setWindowTitle(config.WINDOW_TITLE)
        self.resize(config.WINDOW_WIDTH, config.WINDOW_HEIGHT)
        
        # 创建主体部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        
        # 标题
        title_label = QLabel("欢迎使用图片云上传")
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("font-size: 24px; font-weight: bold; margin: 10px;")
        main_layout.addWidget(title_label)
        
        # 目录输入区域
        dir_layout = QHBoxLayout()
        dir_label = QLabel("上传目录:")
        dir_layout.addWidget(dir_label)
        
        self.dir_input = QLineEdit()
        self.dir_input.setPlaceholderText("请输入上传目录")
        self.dir_input.setText("default")  # 设置默认目录
        dir_layout.addWidget(self.dir_input)
        
        main_layout.addLayout(dir_layout)
        
        # 创建拖放区域提示
        drop_hint = QLabel("拖拽图片到下方区域或点击浏览按钮选择图片")
        drop_hint.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(drop_hint)
        
        # 创建文件浏览按钮
        browse_button = QPushButton("浏览图片")
        browse_button.clicked.connect(self.browse_files)
        main_layout.addWidget(browse_button)
        
        # 创建左右分栏布局
        split_layout = QHBoxLayout()
        
        # 左侧 - 文件列表区域
        left_widget = QWidget()
        left_layout = QVBoxLayout(left_widget)
        left_layout.setContentsMargins(5, 5, 5, 5)
        
        # 文件列表标题
        file_list_label = QLabel("已选择的图片:")
        left_layout.addWidget(file_list_label)
        
        # 文件列表控件
        self.file_list_widget = QListWidget()
        self.file_list_widget.setSelectionMode(QListWidget.SingleSelection)
        self.file_list_widget.itemClicked.connect(self.preview_selected_image)
        self.file_list_widget.setStyleSheet("""
            QListWidget {
                border: 1px solid #aaa;
                border-radius: 5px;
                padding: 5px;
                background: #f8f8f8;
            }
            QListWidget::item {
                border-bottom: 1px solid #eee;
                padding: 5px;
            }
            QListWidget::item:selected {
                background: #e0e0e0;
                color: black;
            }
        """)
        left_layout.addWidget(self.file_list_widget)
        
        # 添加文件操作按钮
        file_actions_layout = QHBoxLayout()
        
        # 删除所选文件按钮
        self.remove_button = QPushButton("删除")
        self.remove_button.clicked.connect(self.remove_selected_file)
        self.remove_button.setEnabled(False)
        file_actions_layout.addWidget(self.remove_button)
        
        # 清空所有文件按钮
        self.clear_button = QPushButton("清空")
        self.clear_button.clicked.connect(self.clear_all_files)
        self.clear_button.setEnabled(False)
        file_actions_layout.addWidget(self.clear_button)
        
        left_layout.addLayout(file_actions_layout)
        
        # 右侧 - 图片预览区域
        right_widget = QWidget()
        right_layout = QVBoxLayout(right_widget)
        right_layout.setContentsMargins(5, 5, 5, 5)
        
        # 预览标题
        preview_label = QLabel("图片预览:")
        right_layout.addWidget(preview_label)
        
        # 预览区域
        self.preview_area = QLabel()
        self.preview_area.setAlignment(Qt.AlignCenter)
        self.preview_area.setMinimumSize(300, 300)
        self.preview_area.setStyleSheet("""
            QLabel {
                border: 1px solid #aaa;
                border-radius: 5px;
                background: #f8f8f8;
            }
        """)
        self.preview_area.setText("请选择图片进行预览")
        right_layout.addWidget(self.preview_area)
        
        # 图片信息标签
        self.image_info_label = QLabel()
        right_layout.addWidget(self.image_info_label)
        
        # 添加左右两侧到分栏布局
        split_layout.addWidget(left_widget, 1)  # 左侧占比较小
        split_layout.addWidget(right_widget, 2)  # 右侧占比较大
        
        # 添加分栏布局到主布局
        main_layout.addLayout(split_layout, 1)  # 使分栏布局占据主要空间
        
        # 进度显示区域
        progress_group = QWidget()
        progress_layout = QVBoxLayout(progress_group)
        
        self.total_progress_label = QLabel("总体进度:")
        progress_layout.addWidget(self.total_progress_label)
        
        self.total_progress = QProgressBar()
        progress_layout.addWidget(self.total_progress)
        
        self.file_progress_label = QLabel("当前文件进度:")
        progress_layout.addWidget(self.file_progress_label)
        
        self.file_progress = QProgressBar()
        progress_layout.addWidget(self.file_progress)
        
        self.current_file_label = QLabel("")
        progress_layout.addWidget(self.current_file_label)
        
        main_layout.addWidget(progress_group)
        progress_group.setVisible(False)
        self.progress_group = progress_group
        
        # 上传按钮
        self.upload_button = QPushButton("开始上传")
        self.upload_button.clicked.connect(self.start_upload)
        self.upload_button.setEnabled(False)  # 初始禁用，直到选择文件
        main_layout.addWidget(self.upload_button)
        
        # 设置拖放支持
        self.setAcceptDrops(True)
    
    def preview_selected_image(self, item):
        """预览选中的图片"""
        if item is None:
            return
            
        file_path = item.data(Qt.UserRole)
        if not file_path or not os.path.exists(file_path):
            self.preview_area.setText("图片文件不存在")
            self.image_info_label.setText("")
            self.current_preview_file = None
            return
            
        self.current_preview_file = file_path
        
        try:
            # 使用QImageReader正确读取图片方向
            reader = QImageReader(file_path)
            reader.setAutoTransform(True)  # 自动应用EXIF方向信息
            
            # 获取实际尺寸
            original_size = reader.size()
            width = original_size.width()
            height = original_size.height()
            
            # 检查是否有效尺寸
            if width <= 0 or height <= 0:
                # 如果无法获取尺寸，尝试直接加载来获取尺寸
                image = QImage(file_path)
                if not image.isNull():
                    width = image.width()
                    height = image.height()
                else:
                    self.preview_area.setText("无法加载图片")
                    self.image_info_label.setText("")
                    return
            
            # 获取图片并应用EXIF方向
            image = reader.read()
            if image.isNull():
                # 如果读取失败，尝试直接加载
                image = QImage(file_path)
                if image.isNull():
                    self.preview_area.setText("无法加载图片")
                    self.image_info_label.setText("")
                    return
            
            # 确保我们使用的是应用了EXIF方向后的尺寸
            width = image.width()
            height = image.height()
            is_portrait = height > width
            
            # 获取预览区域尺寸
            preview_width = self.preview_area.width() - 20  # 留出边距
            preview_height = self.preview_area.height() - 20
            
            # 根据图片方向优化显示
            if is_portrait:
                # 竖屏图片 - 限制高度为预览区域高度
                scaled_height = min(height, preview_height)
                scaled_width = int(width * scaled_height / height)
                
                # 确保宽度不超过预览区域
                if scaled_width > preview_width:
                    scaled_width = preview_width
                    scaled_height = int(height * scaled_width / width)
            else:
                # 横屏图片 - 限制宽度为预览区域宽度
                scaled_width = min(width, preview_width)
                scaled_height = int(height * scaled_width / width)
                
                # 确保高度不超过预览区域
                if scaled_height > preview_height:
                    scaled_height = preview_height
                    scaled_width = int(width * scaled_height / height)
            
            print(f"图片 {os.path.basename(file_path)} - 原始尺寸: {width}x{height}, 缩放尺寸: {scaled_width}x{scaled_height}, 竖向: {is_portrait}")
            
            # 创建适合的QPixmap并保持原始宽高比
            pixmap = QPixmap.fromImage(image).scaled(
                scaled_width, scaled_height,
                Qt.KeepAspectRatio, 
                Qt.SmoothTransformation
            )
            
            # 设置预览图片
            self.preview_area.setPixmap(pixmap)
            
            # 显示图片信息
            file_size = os.path.getsize(file_path) / 1024  # KB
            orientation = "竖向" if is_portrait else "横向"
            self.image_info_label.setText(
                f"文件名: {os.path.basename(file_path)}\n"
                f"尺寸: {width}x{height} 像素\n"
                f"大小: {file_size:.1f} KB\n"
                f"方向: {orientation}"
            )
            
            # 启用删除按钮
            self.remove_button.setEnabled(True)
            
        except Exception as e:
            self.preview_area.setText(f"预览错误: {str(e)}")
            self.image_info_label.setText("")
            print(f"预览图片错误: {str(e)}")
    
    def remove_selected_file(self):
        """删除当前选中的文件"""
        current_item = self.file_list_widget.currentItem()
        if current_item is None:
            return
            
        file_path = current_item.data(Qt.UserRole)
        if file_path in self.selected_files:
            self.selected_files.remove(file_path)
            
            # 从列表中移除
            row = self.file_list_widget.row(current_item)
            self.file_list_widget.takeItem(row)
            
            # 清除预览
            if self.current_preview_file == file_path:
                self.preview_area.clear()
                self.preview_area.setText("请选择图片进行预览")
                self.image_info_label.setText("")
                self.current_preview_file = None
                self.remove_button.setEnabled(False)
            
            # 更新按钮状态
            if not self.selected_files:
                self.upload_button.setEnabled(False)
                self.clear_button.setEnabled(False)
                
    def clear_all_files(self):
        """清空所有已选文件"""
        self.selected_files = []
        self.file_list_widget.clear()
        self.preview_area.clear()
        self.preview_area.setText("请选择图片进行预览")
        self.image_info_label.setText("")
        self.current_preview_file = None
        self.upload_button.setEnabled(False)
        self.clear_button.setEnabled(False)
        self.remove_button.setEnabled(False)
    
    def dragEnterEvent(self, event: QDragEnterEvent):
        """拖拽进入事件处理"""
        print("主窗口接收到拖拽进入事件")
        if event.mimeData().hasUrls():
            print("接受拖拽，有URLs")
            event.accept()
        else:
            print("忽略拖拽，无URLs")
            event.ignore()
    
    def dragMoveEvent(self, event):
        """拖拽移动事件处理"""
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()
            
    def dragLeaveEvent(self, event):
        """拖拽离开事件处理"""
        pass
    
    def dropEvent(self, event: QDropEvent):
        """拖拽放下事件处理"""
        print("主窗口接收到拖拽放下事件")
        file_paths = []
        for url in event.mimeData().urls():
            file_path = url.toLocalFile()
            print(f"拖放的文件: {file_path}")
            ext = os.path.splitext(file_path.lower())[1]
            
            # 检查是否为支持的图片格式
            if ext in config.ALLOWED_EXTENSIONS:
                file_paths.append(file_path)
                print(f"接受的图片: {file_path}")
            else:
                print(f"不支持的格式: {ext}")
        
        if file_paths:
            print(f"添加 {len(file_paths)} 个文件")
            self.add_files(file_paths)
        else:
            print("没有有效的图片文件")
    
    def browse_files(self):
        """打开文件选择对话框"""
        options = QFileDialog.Options()
        file_filter = "图片文件 ({})".format(" ".join(["*" + ext for ext in config.ALLOWED_EXTENSIONS]))
        files, _ = QFileDialog.getOpenFileNames(
            self, "选择图片", "", file_filter, options=options
        )
        
        if files:
            self.add_files(files)
    
    def add_files(self, file_paths):
        """添加图片文件到上传列表"""
        # 去除重复文件
        new_file_paths = []
        for path in file_paths:
            # 标准化路径以便比较
            normalized_path = os.path.normpath(path)
            if normalized_path not in [os.path.normpath(p) for p in self.selected_files]:
                new_file_paths.append(normalized_path)
            else:
                print(f"跳过重复文件: {path}")
        
        # 如果没有新文件，直接返回
        if not new_file_paths:
            QMessageBox.information(self, "提示", "所选文件已全部添加，没有新文件")
            return
            
        # 限制文件数量
        remaining_slots = config.MAX_FILES - len(self.selected_files)
        if remaining_slots <= 0:
            QMessageBox.warning(self, "文件数量超限", f"最多只能选择{config.MAX_FILES}个文件")
            return
        
        if len(new_file_paths) > remaining_slots:
            new_file_paths = new_file_paths[:remaining_slots]
            QMessageBox.information(self, "部分文件已添加", 
                               f"已添加{remaining_slots}个文件，达到最大数量限制{config.MAX_FILES}")
        
        # 更新已选文件列表
        self.selected_files.extend(new_file_paths)
        
        # 更新文件列表显示
        for file_path in new_file_paths:
            filename = os.path.basename(file_path)
            item = QListWidgetItem(filename)
            item.setData(Qt.UserRole, file_path)  # 存储完整路径
            self.file_list_widget.addItem(item)
        
        # 自动选择第一个新添加的文件进行预览
        if self.current_preview_file is None and new_file_paths:
            self.file_list_widget.setCurrentRow(0)
            self.preview_selected_image(self.file_list_widget.item(0))
        
        # 启用上传按钮和清空按钮
        self.upload_button.setEnabled(True)
        self.clear_button.setEnabled(True)
    
    def start_upload(self):
        """开始上传流程"""
        if not self.selected_files:
            QMessageBox.warning(self, "无选中文件", "请先选择要上传的图片")
            return
        
        # 获取用户输入的目录
        upload_dir = self.dir_input.text().strip()
        if not upload_dir:
            QMessageBox.warning(self, "上传目录为空", "请输入上传目录")
            return
        
        # 禁用控件
        self.upload_button.setEnabled(False)
        self.file_list_widget.setEnabled(False)
        self.remove_button.setEnabled(False)
        self.clear_button.setEnabled(False)
        self.dir_input.setEnabled(False)
        
        # 显示进度区域
        self.progress_group.setVisible(True)
        self.total_progress.setValue(0)
        self.file_progress.setValue(0)
        self.current_file_label.setText("")
        
        # 创建并启动上传线程
        self.upload_thread = UploadThread(self.selected_files, upload_dir)
        self.upload_thread.update_progress.connect(self.update_total_progress)
        self.upload_thread.update_file_progress.connect(self.update_file_progress)
        self.upload_thread.upload_finished.connect(self.upload_completed)
        self.upload_thread.start()
    
    def update_total_progress(self, progress, current_file):
        """更新总体进度"""
        self.total_progress.setValue(progress)
        self.current_file_label.setText(f"正在上传: {current_file}")
    
    def update_file_progress(self, progress):
        """更新当前文件进度"""
        self.file_progress.setValue(progress)
    
    def upload_completed(self, success_files, failed_files):
        """上传完成处理"""
        # 隐藏进度区域
        self.progress_group.setVisible(False)
        
        # 启用控件
        self.file_list_widget.setEnabled(True)
        self.dir_input.setEnabled(True)
        
        # 显示结果
        success_count = len(success_files)
        failed_count = len(failed_files)
        
        if failed_count == 0:
            QMessageBox.information(
                self, "上传完成", f"所有{success_count}个文件上传成功!"
            )
            # 上传成功后清空列表
            self.clear_all_files()
        else:
            failed_files_str = "\n".join([os.path.basename(f[0]) for f in failed_files[:5]])
            if len(failed_files) > 5:
                failed_files_str += f"\n... 等{len(failed_files)-5}个文件"
                
            QMessageBox.warning(
                self, "部分上传失败", 
                f"成功: {success_count}个文件\n失败: {failed_count}个文件\n\n失败文件列表:\n{failed_files_str}"
            )
            
            # 从列表中移除成功上传的文件
            success_paths = [f[0] for f in success_files]
            new_selected_files = []
            
            for i in range(self.file_list_widget.count()-1, -1, -1):
                item = self.file_list_widget.item(i)
                file_path = item.data(Qt.UserRole)
                
                if file_path in success_paths:
                    self.file_list_widget.takeItem(i)
                else:
                    new_selected_files.append(file_path)
            
            self.selected_files = new_selected_files
            
            # 根据新列表更新按钮状态
            self.upload_button.setEnabled(len(self.selected_files) > 0)
            self.clear_button.setEnabled(len(self.selected_files) > 0)
            
            # 更新预览区域
            if self.current_preview_file in success_paths:
                self.current_preview_file = None
                self.preview_area.clear()
                self.preview_area.setText("请选择图片进行预览")
                self.image_info_label.setText("")
                self.remove_button.setEnabled(False)
                
            # 选择一个新的项目预览
            if self.file_list_widget.count() > 0:
                self.file_list_widget.setCurrentRow(0)
                self.preview_selected_image(self.file_list_widget.item(0))

def main():
    """程序入口函数"""
    app = QApplication(sys.argv)
    window = ImageUploaderApp()
    window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main() 